package com.zzzy.cont.service.mycon;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzzy.common.exception.WarningException;
import com.zzzy.common.util.AssertUtil;
import com.zzzy.common.vo.PageResult;
import com.zzzy.common.vo.SortingField;
import com.zzzy.cont.common.enums.ConStatusEnum;
import com.zzzy.cont.dao.entity.ConFile;
import com.zzzy.cont.dao.entity.Contract;
import com.zzzy.cont.dto.ContractStatusCountDto;
import com.zzzy.cont.service.ConFileHistoryService;
import com.zzzy.cont.service.ConNotifyMessageService;
import com.zzzy.cont.service.ConService;
import com.zzzy.cont.service.ConUserOperateLinkService;
import com.zzzy.cont.vo.contract.my.MyConButtonRes;
import com.zzzy.cont.vo.contract.my.MyConPageReq;
import com.zzzy.cont.vo.contract.my.MyConStatisticsRes;
import com.zzzy.framework.common.util.SecurityUtils;
import com.zzzy.framework.common.util.SortFieldUtil;
import com.zzzy.framework.core.mybatis.query.LambdaQueryWrapperE;
import com.zzzy.framework.dto.LoginUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class MyConService extends ConService {

    @Resource
    protected ConFileHistoryService conFileHistoryService;
    @Resource
    protected ConNotifyMessageService conNotifyMessageService;
    @Resource
    private ConUserOperateLinkService conUserOperateLinkService;

    public PageResult<Contract> getMyConPage(MyConPageReq queryReq) {
        LambdaQueryWrapperE<Contract> queryWrapperE = new LambdaQueryWrapperE<>();

        queryWrapperE.eq(Contract::getUserId, SecurityUtils.getLoginUser().getId())
                .likeIfPresent(Contract::getName, queryReq.getName())
                .likeIfPresent(Contract::getConNo, queryReq.getConNo())
                .likeIfPresent(Contract::getOrderNo, queryReq.getOrderNo())
                .likeIfPresent(Contract::getTradeType, queryReq.getTradeType())
                .likeIfPresent(Contract::getConType, queryReq.getConType())
                .likeIfPresent(Contract::getTradeCompany, queryReq.getTradeCompany())
                .likeIfPresent(Contract::getHasPeriod, queryReq.getHasPeriod())
                .eqIfPresent(Contract::getStatus, queryReq.getStatus())
                .likeIfPresent(Contract::getOperatorName, queryReq.getOperatorName())
                .betweenIfPresent(Contract::getUpdateTime, queryReq.getBeginUpdateTime()
                        , Objects.nonNull(queryReq.getEndUpdateTime()) ? queryReq.getEndUpdateTime().plusDays(1) : null);
        if (StringUtils.isBlank(queryReq.getStatus())) {
            queryWrapperE.orderByDesc(Contract::getId);
        } else {
            queryWrapperE.orderByDesc(Contract::getUpdateTime).orderByDesc(Contract::getId);
        }
        Set<SortingField> sortingFieldSet = SortFieldUtil.getSortingFields(Contract.class, queryReq.getOrderField(), queryReq.getOrderRule());
        return baseMapper.selectPage(queryReq, sortingFieldSet, queryWrapperE);
    }

    @Transactional
    public void deleteById(Long id) {
        Contract contract = getConByIdForUpdate(id);
        AssertUtil.isEquals(ConStatusEnum.DRAFT.getValue(), contract.getStatus(), "只有起草中合同可删除,其他状态只能作废");
        baseMapper.deleteById(id);
        //删除文件信息
        conFileService.remove(new LambdaQueryWrapper<ConFile>().eq(ConFile::getConId, id));
        conActivityNoteService.deleteByConId(id);
        conFileHistoryService.deleteByConId(id);
    }

    public MyConButtonRes getButton(Long id) {
        Contract contract = getConById(id);
        MyConButtonRes buttonRes = new MyConButtonRes();
        boolean isArchived = ConStatusEnum.ARCHIVED.getValue().equals(contract.getStatus());
        boolean isCancel = ConStatusEnum.CANCEL.getValue().equals(contract.getStatus());
        if (isArchived || isCancel){
            return buttonRes;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        //是否当前可操作人
        boolean isCurrentOperator = contract.getOperatorId().equals(loginUser.getId());
        //是否创建人
        boolean isCreateUser = contract.getUserId().equals(loginUser.getId());
        boolean isDraft = ConStatusEnum.DRAFT.getValue().equals(contract.getStatus());
        boolean isAudit = ConStatusEnum.AUDIT.getValue().equals(contract.getStatus());
        boolean isSign = ConStatusEnum.SIGN.getValue().equals(contract.getStatus());
        boolean isFulfill = ConStatusEnum.FULFILL.getValue().equals(contract.getStatus());
        boolean isArchiving = ConStatusEnum.ARCHIVING.getValue().equals(contract.getStatus());
        buttonRes.setEdit(isCurrentOperator && (isDraft || isAudit));
        //是创建人且为当前处理人,状态为起草中 则可删除
        buttonRes.setDelete(isCreateUser && isCurrentOperator && isDraft);
        buttonRes.setCancel(isCreateUser && isCurrentOperator && !isDraft);
        buttonRes.setChangeFile(buttonRes.isDelete());
        buttonRes.setChangeFileTemplate(buttonRes.isDelete());
        buttonRes.setAddAttachment(isCurrentOperator);
        buttonRes.setDeleteAttachment(true);
        buttonRes.setUploadSignFile(isCreateUser && isCurrentOperator && isSign);
        buttonRes.setReAudit(buttonRes.isUploadSignFile());
        buttonRes.setApply(isCreateUser && isCurrentOperator && (isAudit || isSign || isFulfill|| isArchiving));
        buttonRes.setNext(isCreateUser && isCurrentOperator && (isDraft || isAudit || isSign || isFulfill || isArchiving));
        return buttonRes;
    }

    @Transactional
    public void updateWord(Long id, byte[] byteArray, Integer revisionCount) {
        AssertUtil.isTrue(getButton(id).isEdit(), "用户当前无法修改此合同");
        conFileService.updateWordByConId(id, byteArray, revisionCount);

        Contract contract = getConById(id);
        contract.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(contract);
    }

    @Transactional
    public void updatePdf(Long id, byte[] byteArray, boolean addHistory) {
        AssertUtil.isTrue(hasEditFile(id), "用户当前无法修改此合同");
        conFileService.updatePdfByConId(id, byteArray);

        Contract contract = getConById(id);
        contract.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(contract);
        if (addHistory){
            //添加签订中备份版本备份
            conFileHistoryService.addSigningHistory(id);
        }
    }
    @Transactional
    public void updatePdf(Long id, byte[] byteArray) {
        updatePdf(id, byteArray, true);
    }


    private boolean hasEditFile(Long id) {
        Contract contract = getConById(id);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        boolean isCurrentOperator = contract.getOperatorId().equals(loginUser.getId());
        boolean isDraft = ConStatusEnum.DRAFT.getValue().equals(contract.getStatus());
        boolean isAudit = ConStatusEnum.AUDIT.getValue().equals(contract.getStatus());
        boolean isSign = ConStatusEnum.SIGN.getValue().equals(contract.getStatus());
        return isCurrentOperator && (isDraft || isAudit || isSign);
    }
    public void cancel(Long id) {
        Contract contract = getConByIdForUpdate(id);
        if (ConStatusEnum.DRAFT.getValue().equals(contract.getStatus())
                || ConStatusEnum.ARCHIVED.getValue().equals(contract.getStatus())
                || ConStatusEnum.CANCEL.getValue().equals(contract.getStatus())){
            throw new WarningException("合同状态错误");
        }
        contract.setStatus(ConStatusEnum.CANCEL.getValue());
        contract.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(contract);
        conActivityNoteService.addSysNote(id, "作废合同");

        List<Long> userIdList = conUserOperateLinkService.getOperateLinkUserIdListByConId(id);
        String message = contract.getTradeCompany() +" - "+ contract.getName() + " 已作废";
        conNotifyMessageService.addNotifyMessage(id, userIdList, message);
    }

    public void saveMobilePdfBlob(Long id, byte[] byteArray) {
        conFileService.updateMobilePdfBlob(id, byteArray);
    }

    public MyConStatisticsRes getStatistics() {
        Long userId = SecurityUtils.getLoginUser().getId();
        List<ContractStatusCountDto> statusCountList = baseMapper.selectMyContractStatusCountList(userId);
        Map<String, Long> statusCountMap = statusCountList.stream().collect(Collectors.toMap(ContractStatusCountDto::getStatus, ContractStatusCountDto::getCounts));
        MyConStatisticsRes statisticsRes = new MyConStatisticsRes();
        statisticsRes.setDraftCount(statusCountMap.get(ConStatusEnum.DRAFT.getValue()));
        statisticsRes.setAuditCount(statusCountMap.get(ConStatusEnum.AUDIT.getValue()));
        statisticsRes.setSignCount(statusCountMap.get(ConStatusEnum.SIGN.getValue()));
        statisticsRes.setFulfillCount(statusCountMap.get(ConStatusEnum.FULFILL.getValue()));
        statisticsRes.setArchivingCount(statusCountMap.get(ConStatusEnum.ARCHIVING.getValue()));
        statisticsRes.setArchivedCount(statusCountMap.get(ConStatusEnum.ARCHIVED.getValue()));
        statisticsRes.setCancelCount(statusCountMap.get(ConStatusEnum.CANCEL.getValue()));
        return statisticsRes;
    }
}
